/*************************************************************
 * @file       mac_working.c
 * @brief      MAC层任务接口
 *
 *
 * @version   v0.0
 * @author    xieyoub
 * @data      2017/06/09
 *************************************************************/
 
 #include "mac_working.h"
 #include "dllLayer.h"
 #include "cclMsgParser.h"
 #include "macService.h"
 #include "ipc.h"
 #include <uCOS-II\Source\ucos_ii.h>
 #include "gpio.h"
 
 #include "usart.h"
 /** @addtogroup  MAC层任务
  * 
  *  @{	
  */
	




 /**<  DLL消息队列    */
static Message DLLMsgQueue[MESSAGE_MAX_NUMBER]  = {0};
static uint8_t dllInCursor  = 0;
static uint8_t dllOutCursor  = 0;

 /**<  CCL消息队列    */
static Message CCLMsgQueue[MESSAGE_MAX_NUMBER]  = {0};
static uint8_t cclInCursor = 0;
static uint8_t cclOutCursor = 0;
 

/**@brief   消息队列中加入一条消息
  * 
  * @param type 消息类型
  * @param id   消息id
  * @param v    消息v参数
  * @param p    消息p参数
  * @return void
  * @note
  */
void DLL_PostMessage(uint16_t type, uint16_t id, int v, uintptr_t p)
{
#ifdef USE_CRITICAL_WHEN_POST 
   
#if OS_CRITICAL_METHOD == 3u	 
	 OS_CPU_SR cpu_sr  = 0u;
#endif	
	 OS_ENTER_CRITICAL();	
#endif	
	
	 DLLMsgQueue[dllInCursor].type  = type;
	 DLLMsgQueue[dllInCursor].id    = id;
	 DLLMsgQueue[dllInCursor].v     = v;
	 DLLMsgQueue[dllInCursor].p     = p;
	 
	 dllInCursor  = (dllInCursor + 1) % MESSAGE_MAX_NUMBER; 
    
//     if(dllInCursor == dllOutCursor){
//         printf("DLL msg queue gg\n");
//     }
     
#ifdef USE_CRITICAL_WHEN_POST 	
	 OS_EXIT_CRITICAL();	
#endif     
}


/**@brief   窥探消息队列中是否存在消息
  * 
  * 
  * @return 存在消息返回true，否则返回false
  * @note
  */
bool DLL_PeekMessage(Message* pMsg)
{
	 if(dllOutCursor != dllInCursor){
			 memcpy(pMsg, &(DLLMsgQueue[dllOutCursor]),  sizeof(Message));
			 dllOutCursor  = (dllOutCursor +1) % MESSAGE_MAX_NUMBER;
#ifndef NO_PEEK_PROC         
			 return true;
#endif         
		}
		return false;
}

/**@brief   消息队列中加入一条消息
  * 
  * @param type 消息类型
  * @param id   消息id
  * @param v    消息v参数
  * @param p    消息p参数
  * @return void
  * @note
  */
void CCL_PostMessage(uint16_t type, uint16_t id, int v, uintptr_t p)
{
    
#ifdef USE_CRITICAL_WHEN_POST     
#if OS_CRITICAL_METHOD == 3u	 
	 OS_CPU_SR cpu_sr  = 0u;
#endif	
	

	 OS_ENTER_CRITICAL();	
#endif

	
	 CCLMsgQueue[cclInCursor].type  = type;
	 CCLMsgQueue[cclInCursor].id    = id;
	 CCLMsgQueue[cclInCursor].v     = v;
	 CCLMsgQueue[cclInCursor].p     = p;
	
	 cclInCursor  = (cclInCursor +1) % MESSAGE_MAX_NUMBER;
    
//     if(cclInCursor == cclOutCursor){
//         printf("CCL msg queue gg\n");
//     }

#ifdef USE_CRITICAL_WHEN_POST 
	 OS_EXIT_CRITICAL(); 
#endif     
}


/**@brief   窥探消息队列中是否存在消息
  * 
  * 
  * @return 存在消息返回true，否则返回false
  * @note
  */
bool CCL_PeekMessage(Message* pMsg)
{
	 if(cclOutCursor != cclInCursor){
		 memcpy(pMsg,&(CCLMsgQueue[cclOutCursor]), sizeof(Message));
		 cclOutCursor  = (cclOutCursor +1) % MESSAGE_MAX_NUMBER;
         
#ifndef NO_PEEK_PROC       
		 return true;
#endif         
		}
		return false;
}


 
 /**@brief 	DLL层任务
  * 
  * @param  
  * @return 
  * @note
  */
 void DLLTask(void *p_arg)
 {
	 Message Msg;
	 int id;
     int rxMsgBufferIndex;
     CclPostToDllMsg *cclPostDllMsg;
          
     // 对DLL进行初始化操作
     initDllLayer();
	 while(1)
	 {
        static uint16_t TaskRunningCnt  = 0;
		while(DLL_PeekMessage(&Msg)){
			
            if(Msg.type == IPC_MSG_UART)
            {
                if(Msg.id == UART_MSG_RX3)
                {
//					printf("   rec uart3 msg from fpga, waiting for dll to check ... \n");
                    // 接收到来自串口的消息
                    if(Msg.v >= NUM_FPGA_REC_BYTE_PER_FRAME)
                    {
                        rxMsgBufferIndex = recFpgaData((uint8_t *)Msg.p, 0);
                        if(rxMsgBufferIndex != -1)
                        {
							printf("   dll rec fpga msg,   posting msg to ccl ... \n");
                            // 如果接收到新的帧，则向CCL层推送数据消息
                            CCL_PostMessage(IPC_MSG_DLL, DLL_TO_CCL_MSG_ID, NUM_CCL_MSG_BYTES, getRxDataBufferAddr(rxMsgBufferIndex));
                        }
                    }
                }
                else if(Msg.id == UART_MSG_RX1)
                {
					//printf("   uart rx1   rec notification...\n");
					// 尝试初始化FPGA
					initFpga();
                    // 接收到来自串口的时隙提醒
                    phyNotifyDllForTxData(Msg.v);
                }
            }
            else if(Msg.type == IPC_MSG_CCL)
            {
                // 接收到CCL发来的消息
                cclPostDllMsg = (CclPostToDllMsg *) Msg.p;
				
//				printf("   dll get msg to send, txTimes = %u\n", cclPostDllMsg->txTimes);
				
                sendNewMsg(cclPostDllMsg->dataBuffer, NUM_LDPC_MSG_BYTES, cclPostDllMsg->txTimes, cclPostDllMsg->txFreq, cclPostDllMsg->isAvoid);
            }
            
		}
        
		OSTimeDlyHMSM(0,0,0,5);
        
        TaskRunningCnt++;
        if(TaskRunningCnt > 2000){
            TaskRunningCnt  = 0;
//            printf("DLL task running...\n");
        }
//         Uart0_SendByte('D');
	 }
 }
 
 
 
 /**@brief 	CLL层任务
  * 
  * @param  
  * @return 
  * @note
  */
 void CCLTask(void *p_arg)
 {
	 Message msg;
     FpgaRxData *dllRxdata;
     uint32_t timeStartInMs, timeEndInMs, periodInMs;
      
     // 对CCL相关内容进行初始化
     initCclLayer();
	 while(1)
	 {
         static uint16_t TaskRunningCnt  = 0;
         timeStartInMs = OSTimeGet();
		 while(CCL_PeekMessage(&msg)){
             
			//printf("   rec gui msg, msg.type = %d,  msgId = %d\n", msg.type, msg.id);
			 
             if(msg.type == IPC_MSG_DLL)
             {
//				 printf("   ccl rec msg to parse,  from dll ... \n");
                 // 接收到来自DLL的消息
                 dllRxdata = (FpgaRxData *)msg.p;
                 // 解析并分发处理接收到的消息
                 parseRxMsg(dllRxdata->dataBuffer);
                 // 处理完之后，要将数据标记为已处理
                 dllRxdata->isDealed = true;
             }
             else if(msg.type == IPC_MSG_GUI)
             {
                 // CCL收到来自APP层的消息
                 macPeekAppMsg(&msg);
             }
		 }
         
		 OSTimeDlyHMSM(0,0,0,5);
		 
		 timeEndInMs = OSTimeGet();
         periodInMs = timeEndInMs - timeStartInMs;
		 
         cclTimerTask(periodInMs);
         
         TaskRunningCnt++;
         if(TaskRunningCnt > 2000){
             TaskRunningCnt  = 0;
//             printf("CCL task running...\n");
         }
//          Uart0_SendByte('C');
	 }
 }
 
 
 
 
 